<?php
/**
 * 定义对用户提交代码的处理
 *
 * @todo
 * @author Judas <judasnow@gmail.com>
 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
 */
require_once ('File.php');

class code_process {
	/**#@+
         * @access private
         */
	/**
	 * 保存数据库连接对象
	 *
	 * @var object MDB2
	 */
	private $db ;

	/**
	 * 保存code数据库表对应的对象
	 *
	 * @var object db_obj_code 
	 */
	private $db_obj_code ;

	/**
	 * 保存用于处理用户评测代码请求
	 * 时所要委托的对象
	 *
	 * @var object judge_process
	 */
	private $judge_process ;

	/**
	 * 保存为评测用户代码,系统生成的临时文件
	 * 的文件名以及其路径
	 *
	 * @var string 
	 */
	private $temp_file_path_and_name ;

	/**
	 * 
	 * @access public 
	 * @param object MDB2 $db 
	 * @param array $request
	 */
	function __construct( $db , $request = array() ){ 
		
		$this->db = $db ;

		$this->db_obj_code = new db_obj_code( $db ) ;

		if ( !empty($request) ){
			
			foreach( $request as $k => $v ){
		
				$this->db_obj_code->set( $k , $v ); 
			}
		}
		
		$this->judge_process = new judge_process( $db ) ;		
	}

	/**
	 * 返回该对象所对应的文件名 
	 *
	 * @access public 
	 * @return string 
	 */
	function get_code_file_name(){
		
		return $this->db_obj_code->get( 'code_file_name' );
	}
	function get_modify_time(){
		return $this->db_obj_code->get( 'modify_time' );
	}
	function get_create_time(){
		return $this->db_obj_code->get( 'create_time' );
	}
    	function get_content(){
		return $this->db_obj_code->get( 'content' );
	}
	/**
	 * 为一个某种语言在页面之中显示
	 * 及作为参数提供给后台时的一个转义
	 * 
	 * 如:c语言在页面显示时使用'ANSI C'但是作为
	 * 参数传递给后台评测系统时,会使用简单的'c' 
	 *
	 * @access public
	 * @return string $language 
	 */
	function get_language(){

		$language = $this->db_obj_code->get( 'language' );
		
		switch ( $language ){
			
			case 'ANSI C':
				return 'c';
			default :
				return $language ;
		}

	}

	/**
	 * 得到当前对象代表代码所对应的题号
	 *
	 * @access public 
	 * @return string $problem_no
	 */
	function get_problem_no(){
	
		return $this->db_obj_code->get( 'problem_no' );
	}

	/**
	 * 得到当前对象代表代码所对应的用户名
	 *
	 * @access public 
	 * @return string $username 
	 */
	function get_username(){

		$username = $this->db_obj_code->get( 'username' );
	
		if ( @$_SESSION['username'] != $username ){
			
		//	throw new Exception( '当前用户非代码所有者.' );
		}

		return $username ;
	}
	
	/**
	 * 得到当前对象代表代码所对应的题目的时间
 	 * 限制
	 *
	 * 
	 * @access public 
	 * @return string $time_limit
	 */
	function get_time_limit(){

		return $this->db_obj_code->get( 'time_limit' ); 
	}

	/**
	 * 得到当前对象代表代码所对应的题目的内存
 	 * 限制
	 *
	 * 
	 * @access public 
	 * @return string $mem_limit
	 */
	function get_mem_limit(){

		return $this->db_obj_code->get( 'mem_limit' );
	}

	/**
	 * 根据用户使用的不同的语言,返回不同
	 * 的文件后缀名
	 * 
	 * @access public 
	 * @return string $suffix
	 */
	function create_suffix(){

		$language = $this->db_obj_code->get( 'language' );
		//@todo switch结构的出现
		switch( $language ){
		
			case 'ANSI C':
				return '.c' ;
				break ;
			case 'C++':
				return '.cpp';
				break ;
			default :
				throw new Exception( '用户使用了未知的语言.' );
		}
	}

	/**
	 * 为当前对象代表代码生成文件名
	 * 作为数据表的主键,注意不要同
	 * 评测时使用的临时文件名混淆.
	 *
	 * 文件名格式为: 题号_用户名_提交时间_后缀名
	 *
	 * @access public 
	 * @return string $code_file_name
	 */
	private function create_code_file_name(){
		
		$problem_no = $this->db_obj_code->get('problem_no') ;
		$username = $this->db_obj_code->get('username');
		$suffix = $this->create_suffix();

		$code_file_name = array( $this->db_obj_code->get('problem_no') , 
			$this->db_obj_code->get('username') , time() , $suffix );
		$code_file_name = implode( '_' , $code_file_name );

		return $code_file_name ;
	}

	/**
	 * 保存当前对象所对应的代码到
	 * 数据库之中
	 *
	 * @access public 
	 * @return bool
	 */	
	function save(){
		
		//此处提供的是$request即用户所不能提供的信息
		$code_file_name = $this->create_code_file_name() ;
		$create_time = $modify_time = date("Y-m-d H:i:s",time()+8*60*60) ;
	
		$this->db_obj_code->set( 'code_file_name' , $code_file_name );
		$this->db_obj_code->set( 'create_time' , $create_time ) ;
		$this->db_obj_code->set( 'modify_time' , $modify_time );
		
		return $this->db_obj_code->save();
	}

	/**
	 * 委托给db_obj_code对象的load方法
	 * 
	 * @access public 
	 * @see db_obj::load()
	 */
	function load( $k , $v ){
		
		return $this->db_obj_code->load( $k , $v );
	}

	/**
	 * 为评测代码的请求生成临时的文件
	 * 并保存在指定的目录下
	 * 
	 * @access public
	 * @return bool
	 */
	function create_temp_file_to_judge(){
		//是否要增加名字的复杂性？		
		$temp_file_name = $this->db_obj_code->get('code_file_name');

		$file_content = $this->db_obj_code->get( 'content' );
		
		//real path = /home/web/www/gearman/resource/  
		$e = File::write( '/home/web/www/gearman/resource/'.$temp_file_name , $file_content , FILE_MODE_WRITE);

		if ( PEAR::isError($e) ) {
		
			throw new Exception( $e->getMessage() ) ;
		} 

		$this->temp_file_path_and_name = $temp_file_name ;

		return true ;	
	}

	/**
	 * 返回为评测代码所生成的临时文件的文件名及路径
	 *
	 * @access public
	 * @return string $temp_file_path_and_name
	 */
	function get_temp_file_path_and_name(){
	
		return $this->temp_file_path_and_name;
	}

	/**
	 * 删除为评测所生成的临时文件
	 *
	 * @access public 
	 * @access bool
	 */
	public function delete_temp_file(){

		$this->temp_file_path_and_name ;
		return true ;
	//	return unlink( WWWROOT.$this->temp_file_path_and_name );
	}

	/**
	 * 得到所给用户的所有代码列表
	 *
	 * @access static public
	 * @param object MDB2 $db 
	 * @param string $username
	 * @return array $codes
	 */
	public static function get_all_code_by_user_name( $db , $username ){

		$sql = "SELECT * FROM `code` WHERE username = '$username'";
		$res = $db->query( $sql );
		if ( !$res ){
		
			return false ;
		}

		$rows = $res->fetchAll( MDB2_FETCHMODE_ASSOC );
		return $rows ;
	}

	/**
	 * 为评测当前代码生成调用后台
	 * 程序所需的参数
	 *
	 * @access public 
	 * @return string $arg
	 */
	function create_arg(){
		
		$language = $this->get_language() ;
		
		$code_file_path_and_name = $this->get_temp_file_path_and_name() ;
		$problem_no = $this->get_problem_no();
		$username = $this->get_username();
		$time_limit = $this->get_time_limit();
		$mem_limit = $this->get_mem_limit();
	
		//@todo 此处有问题
		if( empty($username) && empty( $_SESSION['username'] )){
			
			$username = 'anonymous'; 
		}

		$arg = "-L $language -F $code_file_path_and_name -P $problem_no -U $username -TL $time_limit -ML $mem_limit";

		return $arg ;	
	}

	//todo 防止用户重复提交某一代码
	//有没有必要 ?
	private function has_judge(){

		$sql = "SELECT * FROM result WHERE `code_file_name` = ";
	}
	

	/**
	 * 委托judge_process对象进行评测
	 *
	 * @access public 
	 * @return bool
	 */
	function do_judge(){
		
		$this->create_temp_file_to_judge() ;
		$arg = $this->create_arg();

		$result = $this->judge_process->do_judge( $arg );

		$this->delete_temp_file() ;
		return $result ;
	}
	static function delete( $db,$username ){
		$sql = "DELETE FROM code WHERE username ='".$username."'" ;
		$res = $db->query( $sql ); 
		if (PEAR::isError($res)) {
			throw new Exception( '删除出错'.$res->getMessage() );
		}
	}
  static function delete_code_file_name($db, $filename ){
		$sql = "DELETE FROM code WHERE code_file_name='".$filename."'" ;
		$res = $db->query( $sql ); 
		if (PEAR::isError($res)) {
			throw new Exception( '删除出错'.$res->getMessage() );
		}
	}
}
?>
